﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace QRCodeDemo
{
    class SS_SSRLinkHandler
    {
        private String linkType = "";
        private String decodedLink = "";
        public String DecodedLink { get { return decodedLink; } }
        public String Link { set; get; }

        public Dictionary<String, String> GetParams()
        {
            if (String.IsNullOrEmpty(Link))
            {
                return null;
            }
            bool isMatch = Regex.IsMatch(Link, "^ssr?://[\\w\\d_=-]+(@[\\d\\.:]+)?(/\\?plugin=.+)?(#.+)?$");
            Dictionary<String, String> paramsDic = null;
            if (isMatch)
            {
                String[] strArr = Regex.Split(Link, "://");
                linkType = strArr[0].ToLower();
                Link = strArr[1];
                paramsDic = new Dictionary<string, string>();
                if (linkType == "ss")
                {

                    if (Link.Contains("#"))
                    {
                        String remarks = HttpUtility.UrlDecode(Link.Substring(Link.IndexOf('#') + 1));
                        paramsDic.Add("remarks", remarks);
                        Link = Link.Remove(Link.IndexOf('#'));
                        decodedLink = "#" + remarks + decodedLink;
                    }
                    if (Link.Contains("/?plugin="))
                    {
                        String strPluginParam = HttpUtility.UrlDecode(Link.Substring(Link.IndexOf("/?plugin=") + "/?plugin=".Length));
                        String[] arrPluinParam = strPluginParam.Split(new Char[] { ';' }, 2);
                        paramsDic.Add("plugin", arrPluinParam[0]);
                        paramsDic.Add("plugin_opts", arrPluinParam[1]);
                        Link = Link.Remove(Link.IndexOf("/?plugin="));
                        decodedLink = "/?plugin=" + strPluginParam + decodedLink;
                    }
                    if (Link.Contains("@"))
                    {
                        String strParamHostPort = Link.Substring(Link.IndexOf('@') + 1);
                        String[] arrParamHostPort = strParamHostPort.Split(':');
                        paramsDic.Add("server", arrParamHostPort[0]);
                        paramsDic.Add("server_port", arrParamHostPort[1]);
                        Link = Link.Remove(Link.IndexOf('@'));
                        decodedLink = "@" + strParamHostPort + decodedLink;
                    }

                    String strParams = DecodeBase64String(Link);

                    String[] arrParams = strParams.Split(':', '@');
                    paramsDic.Add("method", arrParams[0]);
                    paramsDic.Add("password", arrParams[1]);
                    if (arrParams.Length == 4)
                    {
                        paramsDic.Add("server", arrParams[2]);
                        paramsDic.Add("server_port", arrParams[3]);
                    }

                    decodedLink = "ss://" + strParams + decodedLink;
                }
                else if (linkType == "ssr")
                {
                    // The first decoding
                    Link = Link.Replace('-', '+').Replace('_', '/');
                    String strParams = DecodeBase64String(Link);
                    String[] arrParams = Regex.Split(strParams, "/\\?");
                    String strBaseParams = arrParams[0];
                    String strExtraParams = arrParams[1];
                    String[] arrBaseParams = strBaseParams.Split(':');

                    paramsDic.Add("server", arrBaseParams[0]);
                    paramsDic.Add("server_port", arrBaseParams[1]);
                    paramsDic.Add("protocol", arrBaseParams[2]);
                    paramsDic.Add("method", arrBaseParams[3]);
                    paramsDic.Add("obfs", arrBaseParams[4]);
                    paramsDic.Add("password", arrBaseParams[5] = DecodeBase64String(arrBaseParams[5]));

                    decodedLink = "ssr://" + arrBaseParams[0] + ":" + arrBaseParams[1] + ":" + arrBaseParams[2] + ":" +
                        arrBaseParams[3] + ":" + arrBaseParams[4] + ":" + arrBaseParams[5] + "/?";

                    //The second decoding
                    String[] arrExtraParams = strExtraParams.Split('&');
                    foreach (String param in arrExtraParams)
                    {
                        String[] str = param.Split('=');
                        if (str[0] == "remarks")
                        {
                            paramsDic.Add("remarks_base64", str[1]);
                        }
                        str[1] = str[1].Replace('-', '+').Replace('_', '/');
                        paramsDic.Add(str[0], str[1] = DecodeBase64String(str[1]));
                        decodedLink += str[0] + "=" + str[1] + "&";
                    }
                    decodedLink = decodedLink.Remove(DecodedLink.Length - 1);
                }
            }
            if (paramsDic != null)
            {
                foreach (var item in paramsDic)
                {
                    Console.WriteLine("{0}: {1}", item.Key, item.Value);
                }
            }
            return paramsDic;
        }

        public static String DecodeBase64String(String base64)
        {
            if (!String.IsNullOrEmpty(base64))
            {
                while (base64.Length % 4 != 0)
                {
                    base64 += "=";
                }
                Byte[] byArr = Convert.FromBase64String(base64);
                String text = Encoding.UTF8.GetString(byArr);
                return text;
            }
            return "";
        }

        public static String EncodeBase64String(String text)
        {
            if (!String.IsNullOrEmpty(text))
            {
                Byte[] byArr = Encoding.UTF8.GetBytes(text);
                String base64 = Convert.ToBase64String(byArr);
                return base64.TrimEnd('=');
            }
            return "";
        }
    }
}
